#include "tcp_server.h"

#include "tcp_socket.h"

TcpServer::TcpServer(QObject *parent) : QTcpServer(parent)
{


}

TcpServer::~TcpServer()
{
    qDebug()<<"关闭tcp服务器";
    stop();
}

void TcpServer::incomingConnection(qintptr socketDescriptor)
{
    qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
    qRegisterMetaType<qintptr>("qintptr");

    qDebug()<<"socketDescriptor:"<<socketDescriptor;
    qDebug()<<"TcpServer::incomingConnection(qintptr socketDescriptor):"<<QThread::currentThreadId() << QThread::currentThread();

    //新建客户端连接
    //以下方法弃用，会产生 QObject: Cannot create children for a parent that is in a different thread.
    // QTcpSocket *socket = new QTcpSocket;
    // socket->setSocketDescriptor(socketDescriptor);
    //TcpSocket *client = new TcpSocket(socket, socketDescriptor);

    //解决方法：（创建套接字，在启动Thread后的run函数后，再创建套接字）
    TcpSocket *client = new TcpSocket(socketDescriptor);

    //为每个新连接的套接字建立线程
    QThread *clientThread = new QThread();
    client->moveToThread(clientThread);

    //线程结束后，删除客户端
    connect(clientThread, &QThread::finished,
            client, &TcpSocket::deleteLater);

    connect(clientThread,&QThread::finished,
            clientThread, &QThread::deleteLater);


    //记录套接字
    m_handleTcpClientHash[socketDescriptor] = client;
    m_handleThreadHash[socketDescriptor] = clientThread;

    //关闭tcp服务器
    connect(client, &TcpSocket::clientDisconnected,
            this, &TcpServer::disconnected);

    //传递客户端套接字发送的数据
    // connect(client, &TcpSocket::sendSocketData,
    //         this, &TcpServer::sendClientData);

    ////--->主界面
    //转发发送的数据给主界面
    connect(client, &TcpSocket::conveySendData2MainInterface,
            this, &TcpServer::conveySendData2MainInterface);

    //转发收到的数据
    connect(client, &TcpSocket::receiveData,
            this, &TcpServer::receiveData);

    //传递设备状态
    connect(client, &TcpSocket::conveyEquipmentStatusType,
            this, &TcpServer::conveyEquipmentStatusType);

    //处理登录状态
    connect(this, &TcpServer::sendUserLogInformation,
            client, &TcpSocket::dealUserLogStatus);

    //发送考试情况统计给主界面
    connect(client, &TcpSocket::sendExamSituation,
            this, &TcpServer::sendExamSituation);

    //得到考试的主观评价
    connect(client, &TcpSocket::getExamStepSubjectivePoint,
            this, &TcpServer::getExamStepSubjectivePoint);

    //展示部分表
    connect(client, &TcpSocket::showPartExamTable,
            this, &TcpServer::showPartExamTable);




    ////主界面---->
    //统计考试情况
    connect(this, &TcpServer::calculateExamSituation,
            client, &TcpSocket::calculateExamSituation);

    //把主界面要发送的数据传递给套接字
    //
    connect(this, static_cast<void (TcpServer::*)(const QString &, int port, CommondNumber, QByteArray)>(&TcpServer::sendData2Client),
            client, static_cast<void (TcpSocket::*)(const QString &, int port, CommondNumber, QByteArray)>(&TcpSocket::sendSocketData));

    connect(this, static_cast<void (TcpServer::*)(const QString &, int port, QByteArray)>(&TcpServer::sendData2Client),
            client, static_cast<void (TcpSocket::*)(const QString &, int port, QByteArray)>(&TcpSocket::sendSocketData));



    //发送客户端成功连接的信号
    emit clientConnected(client->getIP(), client->getPort());


    emit conveySendData2MainInterface(client->getIP(), client->getPort(), "客户端上线");

    //连接后加入链表
    clients.append(client);

    //在主线程中创建
    connect(this, &TcpServer::startInitializeTcpSocketFunction,
            client, &TcpSocket::initializeTcpSocketFunction);

    clientThread->start();

    emit startInitializeTcpSocketFunction();
}

bool TcpServer::start(QString ip, int port)
{
    bool ok = listen(QHostAddress(ip), port);
    return ok;
}

void TcpServer::stop()
{
    remove();
    this->close();
}

void TcpServer::closeServer()
{
    foreach (TcpSocket *client, clients) {
        emit clientDisconnected(client->getIP(), client->getPort());

        qDebug()<<QString("%1 %2 客户端下线").arg(client->getIP()).arg(client->getPort());

    }

    //断开连接后从链表中移除
    clients.clear();

    QHash<qintptr,QThread*>::const_iterator threadHash = m_handleThreadHash.constBegin();
    while (threadHash != m_handleThreadHash.constEnd()) {
        threadHash.value()->quit();
        threadHash.value()->wait();
        ++threadHash;
    }
    m_handleThreadHash.clear();
    m_handleTcpClientHash.clear();

    // m_handleThreadHash[socketDescriptor]->quit();
    // m_handleThreadHash[socketDescriptor]->wait();
    // m_handleThreadHash.remove(socketDescriptor);
    // m_handleTcpClientHash.remove(socketDescriptor);
    this->stop();
}

//发送数据
void TcpServer::writeData(const QString &ip, int port,  QByteArray data)
{
    qDebug()<<"writeData(const QString &ip, int port, const QString &data)";
    foreach (TcpSocket *client, clients) {
        if (client->getIP() == ip && client->getPort() == port) {
           // client->sendData(data);
            emit sendData2Client(ip, port, data);
            break;
        }
    }
}

void TcpServer::writeData(QByteArray data)
{
    // qDebug()<<"writeData(const QString &data)";
    foreach (TcpSocket *client, clients) {
        //client->sendData(data);

        emit sendData2Client(client->getIP(), client->getPort(), data);
    }
}

//移除连接
void TcpServer::remove(const QString &ip, int port)
{
    foreach (TcpSocket *client, clients) {
        if (client->getIP() == ip && client->getPort() == port) {
            client->abort();
            break;
        }
    }
}

void TcpServer::remove()
{
    foreach (TcpSocket *client, clients) {
        client->abort();
    }
}

//关闭客户端线程
void TcpServer::closeClientAllThread()
{
    QHash<qintptr,QThread*>::const_iterator threadHash = m_handleThreadHash.constBegin();
    while (threadHash != m_handleThreadHash.constEnd()) {
        threadHash.value()->quit();
        threadHash.value()->wait();
        ++threadHash;
    }

    m_handleTcpClientHash.clear();
}

void TcpServer::closeClientOneThread(qintptr socketDescriptor)
{

    m_handleThreadHash[socketDescriptor]->quit();
    m_handleThreadHash[socketDescriptor]->wait();
    m_handleThreadHash.remove(socketDescriptor);

    m_handleTcpClientHash.remove(socketDescriptor);
}

//关闭套接字
void TcpServer::closeAllSocket()
{
    foreach (TcpSocket *client, clients) {
        emit clientDisconnected(client->getIP(), client->getPort());

        qDebug()<<QString("%1 %2 客户端下线").arg(client->getIP()).arg(client->getPort());

    }

    closeClientAllThread();
    clients.clear();

    this->remove();
}

void TcpServer::closeOneSocket(const QString &ip, int port)
{
    foreach (TcpSocket *client, clients) {
        if(client->getIP() == ip && client->getPort() == port){
            emit clientDisconnected(client->getIP(), client->getPort());

            qDebug()<<QString("%1 %2 客户端下线").arg(client->getIP()).arg(client->getPort());
            closeClientOneThread(client->getSocketDescriptor());
            clients.removeOne(client);
            break;
        }
    }

    this->remove(ip, port);
}

void TcpServer::disconnected(qintptr socketDescriptor)
{
    qDebug()<<"main currentThreadId()"<<this->thread()->currentThreadId();

    qDebug()<<"server currentThreadId()"<<m_handleThreadHash[socketDescriptor]->currentThreadId();

    qDebug()<<"socket currentThreadId()"<<m_handleTcpClientHash[socketDescriptor]->thread()->currentThreadId();

    qDebug()<<"客户端下线";
    TcpSocket *client = (TcpSocket *)sender();
    QString ip = client->getIP();
    int port = client->getPort();
    qDebug()<<"客户端下线的信息"<<ip<<" "<<port;

    emit clientDisconnected(ip, port);

    qDebug()<<QString("%1 %2 客户端下线").arg(ip).arg(port);

    //断开连接后从链表中移除
    clients.removeOne(client);

    // client->m_socket->deleteLater();
    // client->deleteLater();

    //下面的代码会让客户端断开连接后，会退出
    // qDebug()<<"socketDescriptor:"<<socketDescriptor;
    m_handleThreadHash[socketDescriptor]->quit();
    m_handleThreadHash[socketDescriptor]->wait();
    m_handleThreadHash.remove(socketDescriptor);
    m_handleTcpClientHash.remove(socketDescriptor);

}
